"""
    客户端 查看 下载  上传
    服务器 操作界面 提供文件上传下载查看

"""
""" 
    serv_view       提供客户连接 为每个客户分配线程
    serv_model_threading   创建线程 具体功能调用/隔离
    serv_collector   主界面跳转 - 查看功能 下载功能  上传功能  变化点
"""

from socket import *
from threading import Thread
import os
import time

HOST = '0.0.0.0'
PORT = 1944
ADDR = (HOST, PORT)
PATH = '/home/tarena/save_file/'  # 用户下载文件路径


class ServiceView():
    def __init__(self):
        self.__socket = socket()
        self.__socket.bind(ADDR)

    def allot(self):
        """
            建立客户端连接 分配线程
        :return:
        """
        while True:
            self.__socket.listen(5)
            connfd, addr = self.__socket.accept()
            print(f'连接到客户端{addr}')
            t = ServiceModelThreading(connfd)  # 分配线程
            t.start()


class ServiceModelThreading(Thread):

    def __init__(self, connfd):
        """
            为不同客户端创建线程
        :param connfd:
        """
        self.connfd = connfd
        super().__init__()

    def run(self):
        """
           调用服务器功能类，提供主页面选择具体功能
        """
        coller = ServiceCollector(self.connfd)
        coller.jump()
        print(f"用户{self.connfd}退出")


class ServiceCollector():
    """
        为每一个用户服务，提供操作界面
    """

    def __init__(self, connfd):
        self.connfd = connfd

    def jump(self):
        while True:
            data = self.connfd.recv(1024)
            if not data:
                break
            evidence = data.decode().split(' ', 1)[0]
            if evidence == 'LIST':
                self.look_dir()
            elif evidence == 'RETR':
                self.down_load()
            elif evidence == 'STOR':
                self.up_loading()
            elif evidence == 'EXIT':
                break

    def look_dir(self):  # 转列表
        file_list = os.listdir(PATH)
        if not file_list:
            self.connfd.send(b"FAIL")
            print('以告知客户端文件列表为空')
        else:
            self.connfd.send(b'OK')
            # 设定消息边界避免毡包
            files = "\n".join(file_list)
            self.connfd.send(files.encode())
            print('已向客户端发送文件列表')

    def down_load(self):
        filename = self.connfd.recv(1024)
        filepath = PATH + filename.decode()
        try:
            with open(filepath, 'rb') as f:
                self.connfd.send(b'OK')
                print('开始传输文件')
                while True:
                    text = f.read(1024)
                    if not text:
                        break
                    self.connfd.send(text)
            time.sleep(3)
            self.connfd.send(b'##')
            print('文件传输完毕')
        except:
            self.connfd.send(b'FAIL')

    def up_loading(self):
        filename = self.connfd.recv(1024).decode().split('/')[-1]
        print('已收到文件名，现在进行验证')
        if filename not in os.listdir(PATH):  # 判断文件名是否已存在,不存在则告诉服务端开始接收
            self.connfd.send(b'OK')
            print('验证完成，开始接收文件')
            file_path = PATH + filename
            with open(file_path, 'wb') as f:
                while True:
                    text = self.connfd.recv(1024)
                    print('文件接收中...')
                    if text == b'##':
                        break
                    f.write(text)
            print('文件已接收完毕')
        else:
            # 告诉客户端文件名已存在
            print('文件已存在，拒绝接收')
            self.connfd.send(b'FAIL')


if __name__ == '__main__':
    my_service = ServiceView()
    my_service.allot()
